在以后互斥锁就简称是锁,除非遇到递归锁才叫回互斥锁

锁: 保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,使用锁后速度会变慢,但牺牲了速度却保证了数据安全。

锁其实就是将异步执行变成了同步执行

from multiprocessing import Lock

lock = Lock()   # 获取锁
lock.acquire()  # 上锁
print(123)
lock.release()  # 解锁

1. 没有使用锁的抢票例子

  • 如果没有上锁,多个进程修改一个数据的时候,产生数据混乱,
  • 所有人都可以买到票,且剩下的票数也会有问题,因为所有进程几乎在同时读取文件,且读取到的票数都是大于0的,所以所有进程都可以抢到票,且每个进程将读取到的票数减1后再重新写入文件中,后写入的票数就会覆盖前面所写入的票数,这样就会造成数据的混乱或不安全

# 没有上锁的抢票例子

import json
import time
import random
from multiprocessing import Lock
from multiprocessing import Process

# 查看还有多少票
def search(i):
    with open('ticket', encoding='utf-8') as f:
        ticket_num = json.load(f)['count']
        print(i, ticket_num)

# 抢票
def get(i):
    with open('ticket', encoding='utf-8') as f:
        ticket_num = json.load(f)['count']  # 获取现有的票数
    time.sleep(random.random())  # 模拟网路延时
    if ticket_num > 0:
        with open('ticket', 'w', encoding='utf-8') as f:
            json.dump({'count': ticket_num - 1}, f)
        print('%s,买到票了' % i)
    else:
        print('%s,没票了' % i)

def task(i):
    search(i)
    get(i)

if __name__ == '__main__':
    for i in range(5):
        p = Process(target=task, args=(i,))
        p.start()

# ticket.txt -> 执行前

{"count": 10}


# ticket.txt -> 执行后

{"count": 2}

2. 使用锁的抢票例子

  • 每一次只允许一个进程对票数进行查看修改,这样就不会出现上面的情况

# 上锁后的抢票例子

import json
import time
import random
from multiprocessing import Lock
from multiprocessing import Process


# 查看还有多少票
def search(i):
    with open('ticket', encoding='utf-8') as f:
        ticket_num = json.load(f)['count']
        print(i, ticket_num)


# 抢票
def get(i):
    with open('ticket', encoding='utf-8') as f:
        ticket_num = json.load(f)['count']  # 获取现有的票数
    time.sleep(random.random())  # 模拟网路延时
    if ticket_num > 0:
        with open('ticket', 'w', encoding='utf-8') as f:
            json.dump({'count': ticket_num - 1}, f)
        print('%s,买到票了' % i)
    else:
        print('%s,没票了' % i)


def task(i, lock):
    search(i)

    lock.acquire()  # 上锁,每次只允许一个进程进入,且上锁后就不允许其他进程进入执行 lock.acquire() 下方的代码
    get(i)  # 执行抢票
    lock.release()  # 解锁,解锁后下一个进程才允许被进入执行 lock.acquire() 下方的代码


if __name__ == '__main__':
    lock = Lock()  # 获取锁
    for i in range(10):
        p = Process(target=task, args=(i, lock))
        p.start()

# ticket.txt -> 执行前

{"count": 1}


# ticket.txt -> 执行后

{"count": 0}